home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
os2
/
e33el2.zip
/
emacs
/
19.33
/
lisp
/
ediff-ptch.el
< prev
next >
Wrap
Lisp/Scheme
|
1996-07-02
|
21KB
|
563 lines
;;; ediff-ptch.el --- Ediff's patch support
;; Copyright (C) 1996 Free Software Foundation, Inc.
;; Author: Michael Kifer <kifer@cs.sunysb.edu>
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Code:
(defvar ediff-last-dir-patch nil
"Last directory used by an Ediff command for file to patch.")
(defvar ediff-backup-extension
(if (memq system-type '(vax-vms axp-vms emx ms-dos windows-nt windows-95))
"_orig" ".orig")
"Default backup extension for the patch program.")
(defvar ediff-patch-default-directory nil
"*Default directory to look for patches.")
(defvar ediff-context-diff-label-regexp
(concat "\\(" ; context diff 2-liner
"^\\*\\*\\* \\([^ \t]+\\)[^*]+[\t ]*\n--- \\([^ \t]+\\)"
"\\|" ; GNU unified format diff 2-liner
"^--- \\([^ \t]+\\)[^-]+[\t ]*\n\\+\\+\\+ \\([^ \t]+\\)"
"\\)")
"*Regexp matching filename 2-liners at the start of each context diff.")
(defvar ediff-patch-program "patch"
"*Name of the program that applies patches.")
(defvar ediff-patch-options ""
"*Options to pass to ediff-patch-program.")
;; The buffer of the patch file. Local to control buffer.
(ediff-defvar-local ediff-patchbufer nil "")
;; The buffer where patch displays its diagnostics.
(ediff-defvar-local ediff-patch-diagnostics nil "")
;; Map of patch buffer. Has the form:
;; ((filename1 marker1 marker2) (filename2 marker1 marker2) ...)
;; where filenames are files to which patch would have applied the patch;
;; marker1 delimits the beginning of the corresponding patch and marker2 does
;; it for the end.
(ediff-defvar-local ediff-patch-map nil "")
;; strip prefix from filename
;; returns /dev/null, if can't strip prefix
(defsubst ediff-file-name-sans-prefix (filename prefix)
(save-match-data
(if (string-match (concat "^" prefix) filename)
(substring filename (match-end 0))
(concat "/null/" filename))))
;; no longer used
;; return the number of matches of regexp in buf starting from the beginning
(defun ediff-count-matches (regexp buf)
(ediff-eval-in-buffer buf
(let ((count 0) opoint)
(save-excursion
(goto-char (point-min))
(while (and (not (eobp))
(progn (setq opoint (point))
(re-search-forward regexp nil t)))
(if (= opoint (point))
(forward-char 1)
(setq count (1+ count)))))
count)))
;; Scan BUF (which is supposed to contain a patch) and make a list of the form
;; ((filename1 marker1 marker2) (filename2 marker1 marker2) ...)
;; where filenames are files to which patch would have applied the patch;
;; marker1 delimits the beginning of the corresponding patch and marker2 does
;; it for the end. This list is then assigned to ediff-patch-map.
;; Returns the number of elements in the list ediff-patch-map
(defun ediff-map-patch-buffer (buf)
(ediff-eval-in-buffer buf
(let ((count 0)
(mark1 (move-marker (make-marker) (point-min)))
(mark1-end (point-min))
(possible-file-names '("/dev/null" . "/dev/null"))
mark2-end mark2 filenames
beg1 beg2 end1 end2
patch-map opoint)
(save-excursion
(goto-char (point-min))
(setq opoint (point))
(while (and (not (eobp))
(re-search-forward ediff-context-diff-label-regexp nil t))
(if (= opoint (point))
(forward-char 1) ; ensure progress towards the end
(setq mark2 (move-marker (make-marker) (match-beginning 0))
mark2-end (match-end 0)
beg1 (match-beginning 2)
end1 (match-end 2)
beg2 (match-beginning 3)
end2 (match-end 3))
;; possible-file-names is holding the new file names until we
;; insert the old file name in the patch map
;; It is a pair (filename from 1st header line . fn from 2nd line)
(setq possible-file-names
(cons (if (and beg1 end1)
(buffer-substring beg1 end1)
"/dev/null")
(if (and beg2 end2)
(buffer-substring beg2 end2)
"/dev/null")))
;; check for any `Index:' or `Prereq:' lines, but don't use them
(if (re-search-backward "^Index:" mark1-end 'noerror)
(move-marker mark2 (match-beginning 0)))
(if (re-search-backward "^Prereq:" mark1-end 'noerror)
(move-marker mark2 (match-beginning 0)))
(goto-char mark2-end)
(if filenames
(setq patch-map (cons (list filenames mark1 mark2) patch-map)))
(setq mark1 mark2
mark1-end mark2-end
filenames possible-file-names))
(setq opoint (point)
count (1+ count))))
(setq mark2 (point-max-marker)
patch-map (cons (list possible-file-names mark1 mark2) patch-map))
(setq ediff-patch-map (nreverse patch-map))
count)))
;; Fix up the file names in the list using the argument FILENAME
;; Algorithm: find the first file's directory and cut it out from each file
;; name in the patch. Prepend the directory of FILENAME to each file in the
;; patch. In addition, the first file in the patch is replaced by FILENAME.
;; Each file is actually a file-pair of files found in the context diff header
;; In the end, for each pair, we select the shortest existing file.
;; Note: Ediff doesn't recognize multi-file patches that are separated
;; with the `Index:' line. It treats them as a single-file patch.
;;
;; Executes inside the patch buffer
(defun ediff-fixup-patch-map (filename)
(setq filename (expand-file-name filename))
(let ((actual-dir (if (file-directory-p filename)
;; directory part of filename
(file-name-as-directory filename)
(file-name-directory filename)))
;; directory part of the first file in the patch
(base-dir1 (file-name-directory (car (car (car ediff-patch-map)))))
(base-dir2 (file-name-directory (cdr (car (car ediff-patch-map)))))
)
;; chop off base-dirs
(mapcar (function (lambda (triple)
(or (string= (car (car triple)) "/dev/null")
(setcar (car triple)
(ediff-file-name-sans-prefix
(car (car triple)) base-dir1)))
(or (string= (cdr (car triple)) "/dev/null")
(setcdr (car triple)
(ediff-file-name-sans-prefix
(cdr (car triple)) base-dir2)))
))
ediff-patch-map)
;; take the given file name into account
(or (file-directory-p filename)
(string= "/dev/null" filename)
(progn
(setcar (car ediff-patch-map)
(cons (file-name-nondirectory filename)
(file-name-nondirectory filename)))))
;; prepend actual-dir
(mapcar (function (lambda (triple)
(if (and (string-match "^/null/" (car (car triple)))
(string-match "^/null/" (cdr (car triple))))
;; couldn't strip base-dir1 and base-dir2
;; hence, something wrong
(progn
(with-output-to-temp-buffer ediff-msg-buffer
(princ
(format "
The patch file contains a context diff for
%s
%s
However, Ediff cannot infer the name of the actual file
to be patched on your system. If you know the correct file name,
please enter it now.
If you don't know and still would like to apply patches to
other files, enter /dev/null
"
(substring (car (car triple)) 6)
(substring (cdr (car triple)) 6))))
(let ((directory t)
user-file)
(while directory
(setq user-file
(read-file-name
"Please enter file name: "
actual-dir actual-dir t))
(if (not (file-directory-p user-file))
(setq directory nil)
(setq directory t)